﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using AutoMapper;
using KSUNO_EMS.Models;

namespace KSUNO_EMS.Controllers
{
    // [Authorize(Roles = "Manager")]
    [Authorize]
    public class TestManagementController : EmsController
    {
        //
        // GET: /TestManagment/

        public ActionResult Index()
        {
            return (ActionResult)VerifyAccess("Manager") ?? View();
        }

        # region Tests
        public ActionResult CreateTest(TestDTO test)
        {
            try
            {
                if (!ModelState.IsValid)
                    return new ProperJsonResult() { Data = new AjaxResult(false) };
                var dbTest = Mapper.Map<TestDTO, Test>(test);
                dbTest.Description = "";
                Database.Tests.Add(dbTest);
                Database.SaveChanges();
                return new ProperJsonResult { Data = new AjaxResult(true, dbTest) };
            }
            catch (DbEntityValidationException ex)
            {

                throw;
            }

        }

        public ActionResult DeleteTest(int id)
        {
            var test = Database.Tests.SingleOrDefault(e => e.Id == id);
            if (test != null)
            {
               test.ApprovedEmployees.Clear();
               foreach (var question in test.Questions.ToList())
               {
                   foreach (var answer in question.Answers.ToList())
                   {
                       foreach (var result in answer.Results.ToList())
                       {
                           Database.EmployeeTestResults.Remove(result);
                           Database.SaveChanges();
                       }
                       Database.TestQuestionAnswers.Remove(answer);
                       Database.SaveChanges();
                   }
                   Database.TestQuestions.Remove(question);
                   Database.SaveChanges();
               }
               Database.SaveChanges();
               test = Database.Tests.SingleOrDefault(e => e.Id == id); 
                Database.Tests.Remove(test);
                Database.SaveChanges();

                return new ProperJsonResult() { Data = new AjaxResult(true) };
            }
            return new ProperJsonResult() { Data = new AjaxResult(false) };
        }

        public ActionResult ListTests()
        {
            return new ProperJsonResult() { HasDates = true, Data = new AjaxResult(true, Database.Tests.ToList().Select(Mapper.Map<Test, TestDTO>).ToList()) };
        }

        public ActionResult UpdateTest(Models.TestDTO test)
        {
            if (ModelState.IsValid)
            {
                var dbTest = Database.Tests.Include(t => t.Questions).SingleOrDefault(e => e.Id == test.Id);
                if (dbTest != null)
                {
                    dbTest.Name = test.Name;
                    if (dbTest.Questions.Count == test.QuestionsOrder.Length)
                    for (var i = 0; i < test.QuestionsOrder.Length; i++)
                        dbTest.Questions.Single(q => q.Id == test.QuestionsOrder[i]).Number = i + 1;
                    //dbTest.Description = test.Description;
                    Database.SaveChanges();
                    return new ProperJsonResult { Data = new AjaxResult(true) };
                }
            }

            return new ProperJsonResult { Data = new AjaxResult(false) };
        }

        # endregion

        # region Questions
        public ActionResult CreateQuestion(TestQuestionDTO question)
        {
            if (ModelState.IsValid)
            {
                var dbQuestion = Mapper.Map<TestQuestionDTO, TestQuestion>(question);
                dbQuestion.Number = (Database.TestQuestions.Where(q => q.TestId == question.TestId).Max(q => (int?)q.Number) ?? 0) + 1;
                Database.TestQuestions.Add(dbQuestion);
                Database.SaveChanges();

                return new ProperJsonResult() { Data = new AjaxResult(true, Mapper.Map<TestQuestion, TestQuestionDTO>(dbQuestion)) };
            }

            return new ProperJsonResult() { Data = new AjaxResult(false) };
        }

        public ActionResult DeleteQuestion(int id)
        {
            var question = Database.TestQuestions.SingleOrDefault(e => e.Id == id);
            if (question != null)
            {
                //var number = question.Number;
                Database.TestQuestions.Remove(question);
                foreach (var dbQuestion in Database.TestQuestions.Where(q => q.TestId == question.TestId && q.Number > question.Number))
                    dbQuestion.Number--;
                Database.SaveChanges();

                return new ProperJsonResult()
                           {
                               Data = new AjaxResult(true,
                                                     Database.TestQuestions.Where(q => q.TestId == question.TestId).OrderBy(q => q.Number).ToList()
                                                         .Select(Mapper.Map<TestQuestion, TestQuestionDTO>))
                           };
            }
            return new ProperJsonResult() { Data = new AjaxResult(false) };
        }

        public ActionResult ListQuestionsAndAnswers(int id)
        {
            var questions = Database.TestQuestions.Include(q => q.Answers).OrderBy(q => q.Number).ToList()
                .Select(Mapper.Map<TestQuestion, TestQuestionDTO>).ToList();
            foreach (var question in questions)
                question.Answers = question.Answers.OrderBy(a => a.Number).ToList();

            return new ProperJsonResult()
            {
                Data = new AjaxResult(true, questions)
            };
        }

        public ActionResult UpdateQuestion(TestQuestionDTO question)
        {
            if (ModelState.IsValid)
            {
                var dbQuestion = Database.TestQuestions.SingleOrDefault(e => e.Id == question.Id);
                if (dbQuestion != null)
                {
                    dbQuestion.Text = question.Text;
                    for (var i = 0; i < question.AnswersOrder.Length; i++)
                        dbQuestion.Answers.Single(q => q.Id == question.AnswersOrder[i]).Number = i + 1;
                    dbQuestion.CorrectAnswer = dbQuestion.Answers.Single(q => q.Id == question.CorrectAnswerId);

                    Database.SaveChanges();
                    return new ProperJsonResult { Data = new AjaxResult(true) };
                }
            }

            return new ProperJsonResult { Data = new AjaxResult(false) };
        }
        # endregion

        # region Answers
        public ActionResult CreateAnswer(TestQuestionAnswerDTO answer)
        {
            if (ModelState.IsValid)
            {
                var dbAnswer = Mapper.Map<TestQuestionAnswerDTO, TestQuestionAnswer>(answer);
                dbAnswer.Number = (Database.TestQuestionAnswers.Where(q => q.QuestionId == answer.QuestionId).Max(q => (int?)q.Number) ?? 0) + 1;
                Database.TestQuestionAnswers.Add(dbAnswer);
                Database.SaveChanges();

                return new ProperJsonResult() { Data = new AjaxResult(true, Mapper.Map<TestQuestionAnswer, TestQuestionAnswerDTO>(dbAnswer)) };
            }

            return new ProperJsonResult() { Data = new AjaxResult(false) };
        }

        public ActionResult DeleteAnswer(int id)
        {
            var answer = Database.TestQuestionAnswers.SingleOrDefault(e => e.Id == id);
            if (answer != null)
            {
                Database.TestQuestionAnswers.Remove(answer);
                foreach (var dbAnswer in Database.TestQuestionAnswers.Where(q => q.QuestionId == answer.QuestionId && q.Number > answer.Number))
                    dbAnswer.Number--;
                Database.SaveChanges();

                return new ProperJsonResult()
                           {
                               Data =
                                   new AjaxResult(true,
                                                  Database.TestQuestionAnswers.Where(q => q.QuestionId == answer.QuestionId).OrderBy(a => a.Number).ToList()
                                                  .Select(Mapper.Map<TestQuestionAnswer, TestQuestionAnswerDTO>))
                           };
            }

            return new ProperJsonResult() { Data = new AjaxResult(false) };
        }

        public ActionResult UpdateAnswer(int id, string text)
        {
            if (ModelState.IsValid)
            {
                var dbAnswer = Database.TestQuestionAnswers.SingleOrDefault(e => e.Id == id);
                if (dbAnswer != null)
                {
                    dbAnswer.Text = text;
                    Database.SaveChanges();
                    return new ProperJsonResult { Data = new AjaxResult(true) };
                }
            }

            return new ProperJsonResult { Data = new AjaxResult(false) };
        }
        # endregion

        # region Test Results

        public ActionResult ListTestResults(int id)
        {
            return new ProperJsonResult()
                       {
                           HasDates = true,
                           Data = new AjaxResult(true, Database.EmployeeTestResults.Include(r => r.Question).Include(r=>r.Employee)
                                                           .Where(t => t.Question.TestId == id)
                                                           .ToList()
                                                           .GroupBy(g => new { g.EmployeeId, Name = g.Employee.FirstName + " " + g.Employee.LastName })
                                                           .Select(
                                                               g =>
                                                               new TestResultDTO
                                                                   {
                                                                       Id = g.Key.EmployeeId,
                                                                       Name = g.Key.Name,
                                                                       Score = String.Format("{0}/{1}", g.Count(q => q.Answer == q.Question.CorrectAnswer), g.Count())
                                                                   })
                                                           .ToList())
                       };
        }

        public ActionResult ListEmployeeTestResults(int testId, int employeeId)
        {
            var testResult = new EmployeeTestResult();

            return new ProperJsonResult()
                       {
                           HasDates = true,
                           Data = new AjaxResult(true, Database.EmployeeTestResults.Include(r => r.Question.CorrectAnswer).Include(r => r.Question.Answers)
                                                           .Where(t => t.Question.TestId == testId && t.EmployeeId == employeeId)
                                                           .OrderBy(q => q.Question.Number)
                                                           .ToList()
                                                           .Select(
                                                               r =>
                                                               new
                                                                   {
                                                                       Id = r.QuestionId,
                                                                       Number = r.Question.Number,
                                                                       Text = r.Question.Text,
                                                                       CorrectAnswerId = r.Question.CorrectAnswer.Id,
                                                                       EmployeeAnswerId = r.AnswerId,
                                                                       Answers = r.Question.Answers.OrderBy(a => a.Number).Select(a => new {a.Id, a.Text})
                                                                   })
                                                           .ToList())
                       };
        }

        # endregion

        # region Test Approvals

        public ActionResult Approve(int testId, int employeeId)
        {
            Database.Employees.Single(e => e.Id == employeeId).ApprovedTests.Add(Database.Tests.Single(t => t.Id == testId));
            Database.SaveChanges();
            return new ProperJsonResult() {Data = new AjaxResult(true)};
        }

        public ActionResult Revoke(int testId, int employeeId)
        {
            var employee = Database.Employees.Include(e => e.ApprovedTests).Single(e => e.Id == employeeId);
            var approval = employee.ApprovedTests.SingleOrDefault(t => t.Id == testId);
            if (approval != null)
            {
                employee.ApprovedTests.Remove(approval);
                Database.SaveChanges();
            }
            return new ProperJsonResult() {Data = new AjaxResult(true)};
        }

        public ActionResult ListTestApprovals(int id)
        {
            return new ProperJsonResult()
                       {
                           HasDates = true,
                           Data = new AjaxResult(true, Database.Employees.Include(a => a.ApprovedTests)
                                                           .ToList()
                                                           .Select(e => new TestApprovalDTO
                                                                            {
                                                                                Id = e.Id,
                                                                                Employee = e.FirstName + " " + e.LastName,
                                                                                IsApproved = e.ApprovedTests.Any(t => t.Id == id)
                                                                            })
                                                           .ToList())
                       };
        }

        # endregion
    }
}
